
import pymel.core as pm
import maya.cmds as cmds
import utils
import ctrlShape


class PantinNode (pm.nt.Time):
    '''
    Base class of all pantin Node.
    
    param :
    nodeName = name of the node (string)
    '''
    _input = ()
    
    @classmethod
    def _createVirtual (cls):
        pass
    
    @classmethod
    def createVirtual(cls,**kwargs):
        """
        This method is called when no argument is passed to the class, such as:
        
        >>> CharacterNode (name='right')
        CharacterNode(u'right_char')
        
        this method must be a classmethod or staticmethod. If you don't know what that means, just make sure you have
        @classmethod above your createVirtual method, as in this example.
        """
        # pop the _customFlags from kwargs and put it in customFlags
        # test if the needed parameter are there
        customFlag = dict ()
        for key in cls._customFlags.keys() :
            try :
                customFlag [key] = kwargs.pop(key)
            except KeyError :
                try :
                    value = cls._customFlags[key]
                except KeyError :
                    raise TypeError, 'Invalid flag %s' % (key)
                if value != None :
                    customFlag[key] = value
                else :
                    raise AttributeError, '%s is needed to create the node' % (key)
                
        # create the node name, name = characterName + side + name + cls._suffix
        kwargs['name'] = cls.buildName(**customFlag)
        pantNode = pm.createNode('time',**kwargs)
        
        # add attribute for the callback
        pantNode.addAttr('_nodeType',dt='string')
        pantNode._nodeType.set(cls._nodeTypeID)
        pantNode._nodeType.lock()
        
        pantNode.addAttr('_pantin',at='message')
        
        # add the input of the node
        for input in cls._input :
            pantNode.addAttr(input+'_input',at='message',multi=True,indexMatters=False)
        
        cls.setup(pantNode,**customFlag)
        return str(pantNode)
    
    @classmethod
    def _isVirtual( cls, obj, name ):
        """This is the callback for the determining if a Node should become a "virtual" Character or Leg, etc.  
        The name of the method is unimportant, and it could have actually been a regular function instead of a class method.
        Notice that this method is a classmethod, which means it gets passed the class as "cls" instead of an instance as "self".
        
        PyMEL code should not be used inside the callback, only API. 
        """
        # obj is either an MObject or an MDagPath, depending on whether this class is a subclass of DependNode or DagNode, respectively.
        fn = pm.api.MFnDependencyNode(obj)
        try:
            # NOTE: MFnDependencyNode.hasAttribute fails if the attribute does not exist, so we have to try/except it.
            plug = fn.findPlug('_nodeType')
            return cls._nodeTypeID == plug.asString()
        except: pass
        return False
    
    @classmethod
    def setup (cls,**kwags):
        raise NotImplementedError
    
    @classmethod
    def buildName (cls,**kwargs):
        '''
        Build the name of the node.
        '''
        for index in xrange (1,100) :
            name = '%s_%s_%s%#02d_%s'% (kwargs['characterName'], kwargs['side'],kwargs['name'],index,cls._suffix)
            if not pm.objExists(name) :
                return name
            
        
    def getNodeType (self):
        '''
        Return the type of the node.
        '''
        return self._nodeType.get()
    
        
    def connectToParent (self,parentNode):
        '''
        Connect to the parent node.
        
        param :
        parent Node (node to connect)
        '''
        freeInputNumber = len(parentNode._pantin.listConnections())
        self._pantin[0].connect(parentNode._pantin[freeInputNumber])
    
    
    def getParentNode (self):
        '''
        Return the parent node.
        '''
        #return PantNode (self._pantin.outputs()[0])
        return self._pantin.outputs()[0]
    
    def getCharacterNode (self):
        '''
        Return the character node.
        '''
        node = self.getParentNode()
        charNode= node.getCharacterNode()
        return charNode
    
    def getCharacterName (self):
        '''
        Return the name of the character.
        '''
        node = self.getCharacterNode()
        return node.characterName.get()
    
    def listInput (self,completeName=False):
        '''
        Return a list of all input of the node.
        
        param :
        completeName (boolean) : if True return the completeName of the input (ex : master_input)
        '''
        if completeName :
            return [input.split('.')[1] for input in self.listAttr(userDefined=True) if '_input' in input.name()]
        else :
            return [input.split('.')[1].split('_')[0] for input in self.listAttr(userDefined=True) if '_input' in input.name()]
        
    def getSide (self):
        '''
        Return the side of the node.
        
        return the side attribute of the node.
        '''
        return self.split('_')[1]
                
    def listChildNodes (self,type='',side=None):
        '''
        Return a list of all child Node.
        
        Param :
        type : filter node by type (string)
        side : filter node by side (string)
        '''
        for node in utils.flattenList([self.attr(input).inputs() for input in self.listInput(completeName=True)]):
            #node = PantNode(node)
            type = type.capitalize()
            
            if not type and not side:
                yield node
            elif type and node.getNodeType() == type and not side:
                yield node
            elif side and self.getSide() == side and not type :
                yield node
            elif side and type and node.getNodeType() == type and self.getSide() == side:
                yield node
            for underNode in node.listChildNodes(type,side) :
                yield underNode
                
    



class CharacterNode(pm.nt.Transform):
    """ 
    Character node class.
    
    Character is a special node because it don't use unknown node but a transform node.
    it is the root of the hierarchy and don't have proxy node
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy_grp = link to the proxy_grp transform node.
    character_name = name of the caracter
    master_input
    
    param :
    characterName = name of the caracter
    """
    _nodeTypeID = 'CharacterNode'
    _suffix = 'char'
    _customFlags = {'characterName':None}
    
    @classmethod
    def _createVirtual (cls):
        pass
    
    @classmethod
    def createVirtual(cls, **kwargs):
        """
        This method is called when no argument is passed to the class, such as:
        
        >>> CharacterNode (name='right')
        CharacterNode(u'right_char')
        
        this method must be a classmethod or staticmethod. If you don't know what that means, just make sure you have
        @classmethod above your createVirtual method, as in this example.
        """
        # pop the _customFlags from kwargs and put it in customFlags
        customFlag = dict ()
        for key in cls._customFlags.keys() :
            try :
                customFlag [key] = kwargs.pop(key)
            except KeyError :
                try :
                    value = cls._customFlags[key]
                except KeyError :
                    raise TypeError, 'Invalid flag %s' % (key)
                if value != None :
                    customFlag[key] = value
                else :
                    raise AttributeError, '%s is needed to create the node' % (key)
                
        
        # create the name of the node 
        # name = characterName + cls._suffix
        kwargs['name'] = customFlag['characterName'] + '_' + cls._suffix
        charNode = pm.createNode('transform',skipSelect=True,**kwargs)
        
        charNode.addAttr('_nodeType',dt='string')
        charNode._nodeType.set(cls._nodeTypeID)
        charNode._nodeType.lock()
        
        
        cls.setup(charNode,**customFlag)
        return str(charNode)
        
    
    @classmethod
    def _isVirtual( cls, obj, name ):
        """This is the callback for the determining if a Node should become a "virtual" Character or Leg, etc.  
        The name of the method is unimportant, and it could have actually been a regular function instead of a class method.
        Notice that this method is a classmethod, which means it gets passed the class as "cls" instead of an instance as "self".
        
        PyMEL code should not be used inside the callback, only API. 
        """
        # obj is either an MObject or an MDagPath, depending on whether this class is a subclass of DependNode or DagNode, respectively.
        fn = pm.api.MFnDependencyNode(obj)
        try:
            # NOTE: MFnDependencyNode.findPlug fails if the attribute does not exist, so we have to try/except it.
            plug = fn.findPlug('_nodeType')
            value = plug.asString()
            return value == cls._nodeTypeID
        except: pass
        return False
    
    
    @classmethod
    def setup (cls,node,**kwargs):
        '''Add the custom attribute to the node.
        '''
        node.addAttr('characterName',dataType = 'string')
        node.characterName.set(kwargs['characterName'])
            
        node.addAttr ('master_input',at='message',multi=True,indexMatters=False)
        node.addAttr ('proxy_grp',at='message')
        node.addAttr ('ctrl_grp',at='message')
        node.addAttr ('skeleton_grp',at='message')
        node.addAttr ('skeletonMaster_grp',at='message')
            
        utils.lockAndHideAttr(node, all=True)
            
    def getParentNode (self):
        '''
        Character don't have parent node.
        '''
        raise NotImplementedError, '''Character don't have parent node.'''
    
    def connectToParent (self,parentNode):
        '''
        Character don't have parent node.
        '''
        raise NotImplementedError, '''Character don't have parent node.'''
    
    def getCharacterNode (self):
        '''
        Return the characterNode.
        '''
        return self
    
    def buildAllProxy (self):
        '''
        Build the proxy for all nodes.
        '''
        for node in self.master_input.inputs() :
            node.buildProxy()
            for elem in node.listChildNodes() :
                elem.buildProxy()
    
    
    def updateAllProxy (self):
        '''
        Update all the proxy.
        
        Update the color of all the proxyBall
        '''
        for node in self.master_input.inputs() :
            node.updateProxy()
            for elem in node.listChildNodes() :
                elem.updateProxy()
                
    def buildAllSkeleton (self):
        '''
        Build the skeleton for all the nodes
        '''
        for node in self.master_input.inputs() :
            node.buildSkeleton()
            for elem in node.listChildNodes() :
                elem.buildSkeleton()
                
    def buildAllRig (self):
        '''
        Build the rig for all nodes
        '''
        for node in self.master_input.inputs() :
            node.buildRig()
            for elem in node.listChildNodes() :
                elem.buildRig()
    
            
            
class RiggingNode (PantinNode):
    '''
    Base class of all rigging node.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    
    param :
    connectTo
    '''
    @classmethod
    def setup (cls,node,**kwargs):
        node._pantin.connect(kwargs['connectTo'],na=True)
        node.addAttr ('proxy',at='message')
        node.addAttr ('ctrl',at='message',multi=True,indexMatters=False)
        node.addAttr ('jnt',at='message',multi=True,indexMatters=False)
        node.addAttr ('constraint',at='message',multi=True,indexMatters=False)
        node.addAttr ('utilNode',at='message',multi=True,indexMatters=False)
        pm.select(node)

            
    
    def tellWhereConnected (self,riggingNode,completeName=False):
        '''
        Return to witch input the node is connected.
        
        param :
        riggingNode 
        completeName (boolean) : if True return the completeName of the input (ex : master_input)
        '''
       
        for input in self.listInput(completeName=True) :
            if riggingNode in self.attr(input).listConnections(destination=False) :
                if completeName :
                    return input
                else :
                    return input.split('_')[0]
            
    def askWhereConnected (self,completeName=False):
        '''
        Return the input where the node are connected.
        
        param :
        completeName (boolean) : if True return the completeName of the input (ex : master_input)
        '''
        return self.getParentNode().tellWhereConnected(self,completeName)
    
    def inputIsConnected (self,input,completeName=False):
        '''
        Return True if there is someting connected to input.
        
        param :
        input (string) = name of the input to test 
        complete (boolean) = input name is in completeName form (ex : master_input)
        '''
        if completeName :
            if self.attr(input).listConnections() :
                return True
            else :
                return False
        else :
            if self.attr(input+'_input').listConnections() :
                return True
            else :
                return False
            
    def buildProxyNode (self):
        '''
        Build the proxyNode for the node.
        '''
        if not self.proxy.listConnections() :
            characterName,side,name,suffix = self.split('_')
            # side already have a number need to remove it (ex : world01 -> world)
            name = name[:-2]  
            return globals()[self._proxyNode](characterName=characterName,side=side,name=name,connectTo=self.proxy)
        
            
    def buildProxy (self):
        '''
        Build the proxy for the node.
        '''
        self.buildProxyNode()
        for proxyNode in self.proxy.listConnections() :
            return proxyNode.buildProxy()
        
    def deleteProxy (self):
        '''
        Delete the proxy of the node and the proxy for all the children nodes.
        '''
        for input in self.listInput(completeName=True) :
            for node in self.attr(input).listConnections(source=True,destination=False) :
                node.deleteProxy()
                
                
        for proxyNode in self.proxy.listConnections() :
            proxyNode.deleteProxy()
            proxyNode._pantin.disconnect()
            pm.delete(proxyNode)

        
    def updateProxy (self):
        '''
        Update the proxy.
        '''
        for proxyNode in self.proxy.listConnections() :
            return proxyNode.updateProxy()
        
    def delete (self):
        '''
        Delete the node and all the children node.
        '''
        self.deleteProxy()
        
        for input in self.listInput(completeName=True) :
            for node in self.attr(input).listConnections(source=True,destination=False) :
                node.delete()
        
        self._pantin.disconnect()
        pm.delete(self)
        
    def getProxyNode (self):
        '''
        Return the proxyNode Associate with the node.
        '''
        return self.proxy.listConnections()[0]
    
    def skeletonIsBuild (self):
        '''
        If skeleton is build return True else return False.
        '''
        if self.jnt.inputs() :
            return True
        else :
            return False
    
    def buildSkeleton (self):
        '''
        Build the skeleton
        '''
        if not self.skeletonIsBuild() :
            for proxyNode in self.proxy.listConnections() :
                return proxyNode.buildSkeleton()
        
        
    def buildRig (self):
        '''
        Build the rig
        '''
        for proxyNode in self.proxy.listConnections() :
            return proxyNode.buildRig()

        
class TwoJointsNode (RiggingNode):
    '''
    Base class for arm and leg.
    '''
    @classmethod
    def setup (cls,node,**kwargs):
        RiggingNode.setup(node,**kwargs)
        
        for attribute in ['twoJoints','ik','fk'] :
            node.addAttr (attribute,attributeType="bool")
            
        
        
        
    def setTwoJoints (self,val):
        '''
        Set the twoJoints Attribute and if the proxy is build tell it to add or remove the locator.
        
        param :
        val = boolean val to set
        '''
        self.twoJoints.set(val)
        
        if val :
            for proxyNode in self.proxy.listConnections() :
                proxyNode.addTwoJoints()
        else :
            for proxyNode in self.proxy.listConnections() :
                proxyNode.removeTwoJoints()
                
    def ikFK (self,val):
        '''
        Add or remove the ikJnt and fkJnt Attribute.
        
        param :
        val = value to set (boolean)
        '''
        if val :
            try :
                self.addAttr('ikJnt',at='message',multi=True,indexMatters=False)
                self.addAttr('fkJnt',at='message',multi=True,indexMatters=False)
            except :
                pass
        else :
            try :
                self.ikJnt.delete()
                self.fkJnt.delete()
            except :
                pass
            
    def setFk (self,val):
        '''
        Set the fk Attributes.
        
        param :
        val = value to set (boolean)
        '''
        self.fk.set(val)
        
        if self.fk.get() and self.ik.get() :
            self.ikFK(True)
        else :
            self.ikFK(False)
            
    def setIk (self,val):
        '''
        Set the ik Attributes.
        
        param :
        val = value to set (boolean)
        '''
        self.ik.set(val)
        
        if self.fk.get() and self.ik.get() :
            self.ikFK(True)
        else :
            self.ikFK(False)

        
        
        

class WorldNode (RiggingNode):
    '''
    World node class.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    master_input
    
    param :
    connectTo
    characterName
    name (default='world')
    side (default='c')
    '''
    _nodeTypeID = 'WorldNode'
    _suffix = 'world'
    _customFlags = {'connectTo':None,'characterName':None,'name':'world','side':'c'}
    _proxyNode = 'WorldProxyNode'
    _input = ('master',)
    
            
class RootAtomNode (RiggingNode):
    '''
    Root node class.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    master_input
    
    param
    connectTo
    characterName
    name (default='root')
    side (default='c')
    '''
    _nodeTypeID = 'RootAtomNode'
    _suffix = 'root'
    _customFlags = {'connectTo':None,'characterName':None,'name':'root','side':'c'}
    _proxyNode = 'RootAtomProxyNode'
    _input = ('master',)
    
            
            
class RootNode (RiggingNode):
    '''
    Root node class.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    master_input
    left_input
    right_input
    
    param
    connectTo
    characterName
    name (default='root')
    side (default='c')
    '''
    _nodeTypeID = 'RootNode'
    _suffix = 'root'
    _customFlags = {'connectTo':None,'characterName':None,'name':'root','side':'c'}
    _proxyNode = 'RootProxyNode'
    _input = ('master','left','right')
            

class BoneNode (RiggingNode):
    '''
    Simple bone node class.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    side
    master_input
    
    param
    connectTo
    characterName
    name
    side
    '''
    
    _nodeTypeID = 'BoneNode'
    _suffix = 'bone'
    _customFlags = {'connectTo':None,'characterName':None,'name':None,'side':None}
    _proxyNode = 'BoneProxyNode'
    _input = ('master',)

            
            
class LegNode (TwoJointsNode):
    '''
    Leg node class.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    twoJoints
    master_input
    
    param
    connectTo
    characterName
    name (default=leg)
    side
    twoJoints (boolean, default = False)
    '''
    _nodeTypeID = 'LegNode'
    _suffix = 'leg'
    _customFlags = {'connectTo':None,'characterName':None,'name':'leg','side':None}
    _proxyNode = 'LegProxyNode'
    _input = ('master',)
    
    #@classmethod
    #def setup (cls,node,**kwargs):
    #    RiggingNode.setup(node,**kwargs)
    #    
    #    node.addAttr ('twoJoints',attributeType="bool")
    #    node.twoJoints.set (kwargs['twoJoints'])
        
        
        
            
class FootNode (RiggingNode):
    '''
    Foot node class.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    
    param
    connectTo
    characterName
    name (default = foot)
    side
    '''
    _nodeTypeID = 'FootNode'
    _suffix = 'foot'
    _customFlags = {'connectTo':None,'characterName':None,'name':'foot','side':None}
    _proxyNode = 'FootProxyNode'
    
            
class SpineAtomNode (RiggingNode):
    '''
    Spine Atom node class.
    
    Spine Atom have just 1 input and let the user create other with simple bone.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    master_input
    
    param
    connectTo
    characterName
    name (default = spine)
    side (default = c)
    '''
    _nodeTypeID = 'SpineAtomNode'
    _suffix = 'spine'
    _customFlags = {'connectTo':None,'characterName':None,'name':'spine','side':'c'}
    _proxyNode = 'SpineAtomProxyNode'
    _input = ('master',)
    
            
class SpineNode (RiggingNode):
    '''
    Spine node class.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    jointNumber (number of joint in the spine) default = 6
    master_input
    left_input
    right_input
    
    param
    connectTo
    characterName
    name (default = spine)
    side (default = c)
    '''
    _nodeTypeID = 'SpineNode'
    _suffix = 'spine'
    _customFlags = {'connectTo':None,'characterName':None,'name':'spine','side':'c'}
    _proxyNode = 'SpineProxyNode'
    _input = ('master','left','right')
    
    @classmethod
    def setup (cls,node,**kwargs):
        RiggingNode.setup(node,**kwargs)
        
        node.addAttr('jointNumber',at='byte',defaultValue=8)
        
            
class ClavicleNode (RiggingNode):
    '''
    Clavicle node class.
    
    Attribute :
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    master_input
    
    param
    connectTo
    characterName
    name (default = clavicle)
    side
    '''
    _nodeTypeID = 'ClavicleNode'
    _suffix = 'clav'
    _customFlags = {'connectTo':None,'characterName':None,'name':'clavicle','side':None}
    _proxyNode = 'ClavicleProxyNode'
    _input = ('master',)
    
            
class ArmNode (TwoJointsNode):
    '''
    Arm node class.
    
    _pantin
    _nodeType = type of the node
    twoBones
    proxy = input to connect the proxy node
    master_input
    
    param
    connectTo
    characterName
    name (default = arm)
    side
    twoBones (boolean)
    '''
    _nodeTypeID = 'ArmNode'
    _suffix = 'arm'
    _customFlags = {'connectTo':None,'characterName':None,'name':'arm','side':None}
    _proxyNode = 'ArmProxyNode'
    _input = ('master',)
    
    #@classmethod
    #def setup (cls,node,**kwargs):
    #    RiggingNode.setup(node,**kwargs)
    #    
    #    node.addAttr ('twoJoints',attributeType="bool")
    #    node.twoJoints.set (kwargs['twoBones'])
        
class NeckNode (RiggingNode):
    '''
    Neck node class.
    
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    master_input
    
    param
    connectTo
    characterName
    name (default = neck)
    side (default = c)
    '''
    _nodeTypeID = 'NeckNode'
    _suffix = 'neck'
    _customFlags = {'connectTo':None,'characterName':None,'name':'neck','side':'c'}
    _proxyNode = 'NeckProxyNode'
    _input = ('master',)
    
    @classmethod
    def setup (cls,node,**kwargs):
        RiggingNode.setup(node,**kwargs)
        
        node.addAttr('jointNumber',at='byte',defaultValue=1)

            
class HeadNode (RiggingNode):
    '''
    Head node class.
    
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    
    param
    connectTo
    characterName
    name (default = head)
    side (default = c)
    '''
    _nodeTypeID = 'HeadNode'
    _suffix = 'head'
    _customFlags = {'connectTo':None,'characterName':None,'name':'head','side':'c'}
    _proxyNode = 'HeadProxyNode'
    
            
class HandNode (RiggingNode):
    '''
    Hand node class.
    
    _pantin
    _nodeType = type of the node
    proxy = input to connect the proxy node
    fingerNumber
    
    param
    connectTo
    characterName
    name
    side
    thumb = boolean
    fingerNumber = int
    '''
    _nodeTypeID = 'HandNode'
    _suffix = 'hand'
    _customFlags = {'connectTo':None,'characterName':None,'name':'hand','side':None,'thumb':None,'fingerNumber':None}
    _proxyNode = 'HandProxyNode'
    
    @classmethod
    def setup (cls,node,**kwargs):
        RiggingNode.setup(node,**kwargs)
        
        node.addAttr ('fingerNumber',attributeType="byte")
        node.fingerNumber.set(kwargs['fingerNumber'])
        node.addAttr ('thumb',attributeType='bool')
        node.thumb.set(kwargs['thumb'])
        
            
            
            
# *************************
# *      proxy Node       *
# *************************

class RiggingProxyNode (PantinNode):
    '''
    Base class of all proxy.
    '''
    _customFlags = {'connectTo':None,'characterName':None,'name':None,'side':None}
    
    @classmethod
    def setup (cls,node,**kwargs):
        node._pantin.connect(kwargs['connectTo'])
        node.addAttr ('proxyBall',at='message',multi=True,indexMatters=False)
        node.addAttr ('proxyLink',at='message',multi=True,indexMatters=False)
        node.addAttr ('proxySpline',at='message',multi=True,indexMatters=False)
            
        for input in node._pantin.outputs()[0].listInput(completeName=True) :
            node.addAttr (input,at='message',multi=True,indexMatters=False)
            
                
    @staticmethod        
    def templateObj(obj,reference=False):
        '''
        Template the object.
        
        param :
        obj
        reference (boolean) set the drawing overide to reference
        '''
        obj.overrideEnabled.set(True)
        if not reference :
            obj.overrideDisplayType.set(1)
        else :
            obj.overrideDisplayType.set(2)
            
        
        
    def proxyIsBuild (self):
        '''
        Return true if the proxy is build.
        '''
        if self.proxyBall.inputs() or self.proxyLink.inputs():
            return True
        else :
            return False
        
        
    def buildProxyObjectName (self,name=None,type='proxyBall'):
        '''
        Create the name of the proxyObject
        
        param :
        name (string)
        type (default = proxyBall)
        '''
        newName = self[:self.rfind('_')]
        if name :
            name = '_' + name
        newName = newName + name + '_' + type
        return newName
    
    
    def buildProxy (self):
        '''
        Build the proxy objects.
        '''
        raise NotImplementedError
    
    def deleteProxy (self):
        '''
        Delete the proxy objects
        '''
        # find all the userDefined attributes that don't begin by '_' and delete the object that are
        # connected to this attributes.
        for attribute in [attributes for attributes in self.listAttr(userDefined=True) if attributes.split('.')[1][0] != '_']:
            for elem in attribute.inputs() :
                try :
                    elem._pantin.disconnect()
                    pm.delete(elem)
                except :
                    pass
        
        
    def updateProxy (self):
        '''
        Update the color of the proxyBall.
        '''
        for input in self.getParentNode().listInput(completeName=True) :
            if self.proxyIsBuild() :
                proxyBall = self.attr(input).inputs()[0]
                if self.getParentNode().inputIsConnected (input,completeName=True) :
                    self.setProxyBallColor(proxyBall,'blue')
                else :
                    self.setProxyBallColor(proxyBall,'green')

            
        # build a list of all proxyBall coonected to the node that represent a input      
        listProxyBallInput = [self.attr(input).inputs()[0] for input in self.getParentNode().listInput(completeName=True)]
        # build a list of all proxyBall connected to the node.
        # test if the proxyBall are in listProxyBallInput if there are not set they color to red
        [self.setProxyBallColor(proxyBall,'red') for proxyBall in self.proxyBall.listConnections() if proxyBall not in listProxyBallInput]
    
    def buildProxyGrp (self):
        '''
        Build proxy_grp, proxyBall_grp and proxyLinkCurv_grp.
        
        Test if the proxy_grp exist and create if necessary.
        return proxy_grp, proxyBall_grp and proxyLinkCurv_grp
        '''
        characterNode = self.getCharacterNode()
        try :
            proxy_grp = characterNode.proxy_grp.inputs()[0]
            proxyBall_grp = proxy_grp.proxyBall_grp.inputs()[0]
            proxyLinkCurv_grp = proxy_grp.proxyLinkCurv_grp.inputs()[0]
            return proxy_grp, proxyBall_grp, proxyLinkCurv_grp
        
        except IndexError :
            proxys_grpList = list () # list to store all the new grp
            
            characterName = self.getCharacterName()
            proxy_grpName = characterName + '_proxy_grp'
            proxy_grp = pm.group(empty=True,name=proxy_grpName)
            proxy_grp.addAttr('_pantin',at='message')
            proxy_grp.addAttr('proxyBall_grp',at='message')
            proxy_grp.addAttr('proxyLinkCurv_grp',at='message')
            proxy_grp._pantin.connect(characterNode.proxy_grp)
            pm.parent(proxy_grp,characterNode)
            utils.lockAndHideAttr(proxy_grp, all=True)
            
            proxys_grpList.append(proxy_grp)
            
            for name in ['proxyBall_grp','proxyLinkCurv_grp'] :
                proxyTemp_grp = pm.group(empty=True,name=characterName + name)
                proxyTemp_grp.addAttr('_pantin',at='message')
                proxyTemp_grp._pantin.connect(proxy_grp.attr(name))
                pm.parent(proxyTemp_grp,proxy_grp)
                utils.lockAndHideAttr(proxyTemp_grp, all=True)
                
                proxys_grpList.append(proxyTemp_grp)
                
            return proxys_grpList
            
    
    
    # proxyBall -----------------------------------------------------------------------------
    def buildProxyBall (self,color,size,name,inputToConnect=None):
        '''
        Create a proxy Ball
        
        param : color string (green,blue,red)
                size float
                name string
        '''
        self.createProxyBallSG()
        name = self.buildProxyObjectName (name)
        proxyBall = pm.sphere(constructionHistory=False,name=name,ax=(0, 1, 0),radius=size,name=name)[0]
            
        # hide non used attribute of the proxy ball
        utils.lockAndHideAttr(proxyBall, ('sx','sy','sz','visibility'))
        
        self.setProxyBallColor(proxyBall, color)
        proxyBall.addAttr('_pantin',at='message')
        
        proxyBall_grp = self.buildProxyGrp()[1]
        pm.parent (proxyBall,proxyBall_grp)

        self.connectProxyBall(proxyBall,inputToConnect)
        return proxyBall
    
    
    def createProxyBallSG (self):
        '''
        Create the shading group for the proxyBall.
        
        test if the shading group already exist and create it
        '''
        if not pm.objExists ('pantinProxyBlue') :
            proxySN = pm.shadingNode('surfaceShader',asShader=True,name='pantinProxyBlue')
            pm.sets('pantinProxyBlue',renderable=True,empty=1,noSurfaceShader=True,name='pantinProxyBlueSG')
            pm.connectAttr('pantinProxyBlue.outColor','pantinProxyBlueSG.surfaceShader')
            proxySN.outColor = (0,0,1)
            
        if not pm.objExists ('pantinProxyRed') :
            proxySN = pm.shadingNode('surfaceShader',asShader=True,name='pantinProxyRed')
            pm.sets('pantinProxyBlue',renderable=True,empty=1,noSurfaceShader=True,name='pantinProxyRedSG')
            pm.connectAttr(proxySN.outColor,'pantinProxyRedSG.surfaceShader')
            proxySN.outColor = (1,0,0)
            
        if not pm.objExists ('pantinProxyGreen') :
            proxySN = pm.shadingNode('surfaceShader',asShader=True,name='pantinProxyGreen')
            pm.sets('pantinProxyBlue',renderable=True,empty=1,noSurfaceShader=True,name='pantinProxyGreenSG')
            pm.connectAttr(proxySN.outColor,'pantinProxyGreenSG.surfaceShader')
            proxySN.outColor = (0,1,0)
        return True
    
    @staticmethod
    def setProxyBallColor (proxyBall,color):
        '''
        Set the color of the proxy ball.
        
        param :
        proxyBall  = name of the proxy ball (ex:master) -> characterName_RiggingNode_name_proxyBall
        color (string) = red , green, blue
        '''
        if color == 'blue' :
            #pm.sets('pantinProxyBlueSG',forceElement=proxyBall.name())
            cmds.sets(proxyBall.name(),forceElement='pantinProxyBlueSG',e=True,noWarnings=1)
        elif color == 'red' :
            #pm.sets('pantinProxyRedSG',forceElement=proxyBall.name())
            cmds.sets(proxyBall.name(),forceElement='pantinProxyRedSG',e=True,noWarnings=1)
        elif color == 'green' :
            #pm.sets('pantinProxyGreenSG',forceElement=proxyBall.name())
            cmds.sets(proxyBall.name(),forceElement='pantinProxyGreenSG',e=True,noWarnings=1)
            
            
    def connectProxyBallInput(self,ballToConnect,proxyLink=False,proxyLinkName=''):
        '''
        Parent proxy ball to the coresponding proxyBall input.
        
        parente la proxy ball a la proxy qui reprense l'entree ou le Rigging node est connecter
        
        param :
        proxyLink : create a visual link between the 2 proxy ball (boolean)
        proxyLinkName : name to add to the proxyLinkName
        '''
        parentBallName = self.getProxyBallWhereToConnect()
        
        
        pm.parent (ballToConnect,parentBallName)
        if proxyLink :
            self.buildProxyLink(parentBallName,ballToConnect,proxyLinkName)
        return ballToConnect
            
    
    def connectProxyBall (self,proxyBall,inputToConnect=None):
        '''
        Connect the proxy ball to the proxy node.
        '''
        proxyBall._pantin.connect(self.proxyBall,nextAvailable=True)
        if inputToConnect :
            inputToConnect += '_input'
            proxyBall._pantin.connect(self.attr(inputToConnect))
            
    def getProxyBallWhereToConnect (self):
        '''
        Look where the proxy node is connected and return the proxyBall that match.
        '''
        input = self.getParentNode().askWhereConnected(completeName=True)
        
        parentNodeName = self.getParentNode().getParentNode()
        ballWhereToConnect = parentNodeName.proxy.inputs()[0].attr(input).inputs()[0]
        return ballWhereToConnect
        
        
            
    # proxyLink ------------------------------------------------------------------------        
    def buildProxyLink (self,parent1,parent2,name=''):
        '''
        Build a proxy link.
        
        param :
        parent1
        parent2
        name : name to add to the proxy link name (string)
        '''
        curveName = self.buildProxyObjectName(name, type='proxyLinkCurv')
        curve = pm.PyNode (pm.curve(p=[(0, 0, 0), (0, 0, 0)],knot=[0, 1],degree=1,name=curveName))
        # hide all the non used attribute of the curve
        utils.lockAndHideAttr(curve,all=True)
        
        curve.addAttr('_pantin',at='message')
        self.templateObj(curve)
        
        proxyLinkCurv_grp = self.buildProxyGrp()[2]
        pm.parent (curve,proxyLinkCurv_grp)
        
        clustName = self.buildProxyObjectName(name+'Start', type='proxyLinkClust')
        # BUGFIX : curve.cv[2] don't work with pymel 0.9
        startClust = pm.cluster(curve.name()+'.cv[0]',name=clustName)[1]
        startClust.visibility.set(0)
        
        clustName = self.buildProxyObjectName(name+'End', type='proxyLinkClust')
        # BUGFIX : curve.cv[2] don't work with pymel 0.9
        endClust = pm.cluster(curve.name()+'.cv[1]',name=clustName)[1]
        endClust.visibility.set(0)
        
        pm.parent (startClust,parent1)
        startClust.translate.set(0,0,0)
        
        pm.parent (endClust,parent2)
        endClust.translate.set(0,0,0)
        
        self.connectProxyLink(curve)
        return curve,[startClust,endClust]
    
    def connectProxyLink (self,proxyLink):
        '''
        Connect a proxyLink to the proxyNode.
        '''
        proxyLink._pantin.connect(self.proxyLink,nextAvailable=True)
        return True
    
        
    # proxySpline --------------------------------------------------------------------------
    def buildProxySpline (self,name,parent,degree=3):
        '''
        Build a proxy spline.
        
        param :
        name
        parent : object where the cluster will be parented (tuple)
        degree :  degree of the curve (int)
        '''
        # error checking
        if len(parent) < 2 :
            raise ValueError,'minimum number of parent is 2'
        if len(parent) < 4 and degree == 3 :
            raise ValueError,'3 degree curve need a minimum of 4 parent'
        
        curveName = self.buildProxyObjectName('',type='proxySplineCurv')
        
        # build a list of tuple to use as cv coordonate for the new curve a point per parent
        curvePoint = list()
        for index in range(len(parent)) :
            curvePoint.append((0,0,0))
            
        curve = pm.PyNode (pm.curve(p=curvePoint,degree=degree,name=curveName))
        # hide non used attribute of the curve
        utils.lockAndHideAttr(curve,all=True)
        
        
        curve.addAttr('_pantin',at='message')
        
        self.templateObj(curve)
        
        proxyLinkCurv_grp = self.buildProxyGrp()[2]
        pm.parent (curve,proxyLinkCurv_grp)
        
        # build a cluster for every cv of the curve and parent it.
        clustList = list()
        for index in range(len(parent)):
            if index < 10 :
                indexStr = '0' + str(index)
            else :
                indexStr = str(index)
            clustName = self.buildProxyObjectName(indexStr, type='proxyLinkClust')
            # BUGFIX : curve.cv[2] don't work with pymel 0.9
            cvName = curve.name() + '.cv[' + str(index) + ']'
            newCluster = pm.cluster(cvName,name=clustName)[1]
            newCluster.visibility.set(0)
            clustList.append(newCluster)
            pm.parent(newCluster,parent[index])
            newCluster.translate.set(0,0,0)
            # hide non used attribute of the proxyCurv_grp
            utils.lockAndHideAttr(newCluster,all=True)
            
        self.connectProxySpline(curve)
        return curve,clustList
    
    def connectProxySpline (self,proxySpline):
        '''
        Connect a proxySpline to the proxyNode
        '''
        proxySpline._pantin.connect(self.proxySpline,nextAvailable=True)
        return True
    
    # ctrlObject ---------------------------------------------------------------------------
    @staticmethod
    def setColorOveride (obj,color):
        '''
        Enable the drawing overide and set the color.
        
        param :
        obj = object to set the drawing color
        color 
        '''
        objectShape = pm.listRelatives(obj,shapes=True)[0]
        objectShape.overrideEnabled.set(True)
        objectShape.overrideColor.set(color)
    
    
    def setupCtrl (self,obj):
        '''
        Add _pantin and nodeType, set nodeType to none and connect to the parent node.
        '''
        obj.addAttr('_pantin',at='message')
        obj._pantin.connect(self.getParentNode().ctrl,na=True)
        
    # jnt-----------------------------------------------------------------------------------
        
    def buildSkeleton (self):
        '''
        Build the skeleton for the node.
        '''
        raise NotImplementedError
    
    def buildJointName (self,name,side=None):
        '''
        Return name for the joint.
        
        jointName = characterName + side + name + jnt
        
        param :
        name = base of the new name (string) ex : hips,knee,...
        side = side to use in the name (string) ex : left,right,back,...
        '''
        if side :
            for i in xrange (1,100) :
                jointName = '%s_%s_%s%#02d_jnt'%(self.getCharacterName(),side[0],name,i)
                if not pm.objExists(jointName) :
                    return jointName
        else :
            for i in xrange (1,100) :
                jointName = '%s_%s_%s%#02d_jnt'%(self.getCharacterName(),self.getParentNode().getSide(),name,i)
                if not pm.objExists(jointName) :
                    return jointName
        
    def buildJoint (self,name,inputToConnect=None):
        '''
        Build a joint add _pantin and parent it to the skeleton_grp.
        
        if the joint is a input call connectJoint with inputToConnect.
        
        name : base of name of the new joint (string)
        inputToConnect : name of the input of the prowyNode where to connect the joint (string)
        '''
        # if there is a input to connect and this input is not master the node have several input.
        # use the input name to build the side sufix of the joint
        if inputToConnect and not 'master' in inputToConnect :
            jointName = self.buildJointName(name, side=inputToConnect)
        else :
            jointName = self.buildJointName(name)
            
        pm.select(cl=True)
        joint = pm.joint(name=jointName)
        joint.addAttr('_pantin',at='message')
        
        pm.parent(joint,self.buildSkeletonGrp())
        self.connectJoint(joint, inputToConnect)
            
        return joint
        
        
    def connectJoint(self,joint,inputToConnect=None):
        '''
        Connect the joint to the node.
        
        if the joint is a input connect it to the input[1] of the proxy node
        
        param :
        joint : joint to connect (joint)
        inputToConnect : name of the input of the proxyNode where to connect the joint (string)
        '''
        joint._pantin.connect(self.getParentNode().jnt,na=True)
        if inputToConnect :
            inputToConnect += '_input'
            joint._pantin.connect(self.attr(inputToConnect),na=True)
            
        
        
    def buildSkeletonGrp (self):
        '''
        Build skeleton_grp.
        
        Test if the skeleton_grp exist and create if necessary.
        return skeleton_grp
        '''
        try :
            return self.getCharacterNode().skeletonMaster_grp.inputs()[0]
        except IndexError :
            skeleton_grp = pm.group(empty=True,name=self.getCharacterName()+'_skeleton_grp')
            skeleton_grp.addAttr('_pantin',at='message')
            utils.lockAndHideAttr(skeleton_grp, all=True)
            skeleton_grp._pantin.connect(self.getCharacterNode().skeleton_grp)
            pm.parent(skeleton_grp,self.getCharacterNode())
            
            # skeletonMaster_grp is used to move and scale the rig
            skeletonMaster_grp = pm.group(empty=True,name=self.getCharacterName()+'_skeletonMaster_grp')
            skeletonMaster_grp.addAttr ('_pantin',at='message')
            skeletonMaster_grp._pantin.connect(self.getCharacterNode().skeletonMaster_grp)
            skeletonMaster_grp.setParent(skeleton_grp)
            return skeletonMaster_grp
        
    def getJointWhereToConnect (self):
        '''
        Look where the proxy node is connected and return the joint that match.
        '''
        input = self.getParentNode().askWhereConnected(completeName=True)
        # get the grand parent Node legProxy -> leg -> hips
        grandParentNodeName = self.getParentNode().getParentNode()
        # hips -> hipsProxy.right_input -> [proxyBall,joint][1] -> joint
        jointWhereToConnect = grandParentNodeName.proxy.inputs()[0].attr(input).inputs()[1]
        return jointWhereToConnect
    # rig ---------------------------------------------------------------------------------------
    def buildRig (self):
        '''
        Build the rig for the node.
        '''
        pass
    # const --------------------------------------------------------------------------------------
    def buildConstraintName (self,constType,target):
        '''
        Return name for constraint.
        
        param :
        constType : type of constraint (string)
        target : target of the constraint (node)
        '''
        constSuffix = {'point':'pntConst','aim':'aimConst','orient':'orientConst','scale':'sclConst',\
                       'parent':'parConst','parentTrans':'parConstTrans','parentRot':'parConstRot'}
        
        targetNameList = target.name().split('_')
        
        try :
            return '%s_%s_%s%s_%s'%(self.getCharacterName(),targetNameList[1],targetNameList[2],targetNameList[3].capitalize(),\
                                    constSuffix[constType])
        except IndexError :
            # targetName doesn't have a side
            return '%s_%s_%s%s_%s'%(self.getCharacterName(),'c',targetNameList[1],targetNameList[2].capitalize(),\
                                    constSuffix[constType])
        except KeyError :
            raise TypeError , '%s is not a valid constraintType'%(constType)
        
        
        
    def buildConstraint (self,constType,*args,**kwargs):
        '''
        Create a constraint and connect it to the parentNode.
        
        param :
        constType : type of constraint (string)
        the other parameter are the classic parameter of the constraint
        '''
        constTypeDict = {'point':pm.pointConstraint,'aim':pm.aimConstraint,'orient':pm.orientConstraint,\
                         'scale':pm.scaleConstraint,'parent':pm.parentConstraint,'parentTrans':pm.parentConstraint,\
                         'parentRot':pm.parentConstraint}
        
        kwargs['name'] = self.buildConstraintName(constType,args[len(args)-1])
        
        if constType == 'parentRot' :
            kwargs['skipRotate'] = ['x','y','z']
        elif constType == 'parentTrans' :
            kwargs['skipTranslate'] = ['x','y','z']
            
        const = constTypeDict[constType](*args,**kwargs)
        
        const.addAttr('_pantin',at='message')
        const._pantin.connect(self.getParentNode().constraint,na=True)
        
        
    
 
            
             
    
class TwoJointsProxyNode (RiggingProxyNode):
    '''
    Base class for arm and leg proxy.
    '''
    def buildProxy (self):
        raise NotImplementedError
    
    def addTwoJoints (self,name,direction):
        '''
        Add control to the proxyBall to control the placement of 2 joints.
        
        param :
        name (string)
        direction : direction of the 2 locators (string) (horizontal,vertical)
        '''
        # error checking
        if not direction in ('horizontal','vertical') :
            raise ValueError,'''%s is not a valid parameter for direction,(horizontal or vertical)''' % (direction)
        
        
        middleProxyBall = self.proxyBall.inputs()[0]
        
        #if not middleProxyBall.jointPosition.exists() :
        try :
            middleProxyBall.jointPosition.get()
        except AttributeError :
            middleProxyBall.addAttr ('jointPosition',at='double',min=0,keyable=True,defaultValue=0.3)
            middleProxyBall.addAttr ('twoBoneLocator',at='message',multi=True,indexMatters=False)
            
            for suffixLoc in ['A','B'] :
                newLoc = pm.spaceLocator(name=self.buildProxyObjectName(name+suffixLoc, 'loc'))
                
                # bug solve maya don't return the good name for the locator 
                # if a locator whith the same name already exist in a other space
                # maya don't return the name in full path (no |)
                try :
                    newLoc.addAttr ('_pantin',at='message')
                except TypeError :
                    newLoc = pm.PyNode ('|'+ newLoc)
                    newLoc.addAttr ('_pantin',at='message')
                    
                newLoc._pantin.connect(middleProxyBall.twoBoneLocator,na=True)
                self.templateObj(newLoc,reference=True)
                newLoc.localScale.set(0.2,0.2,0.2)
                pm.parent(newLoc,middleProxyBall)
                newLoc.translate.set(0,0,0)
            
            invNode = pm.createNode ('multiplyDivide',name=self.buildProxyObjectName(name+'TwoJoints','inv'))
            
            if direction == 'horizontal' :
                invNode.input2X.set(-1)
                middleProxyBall.jointPosition.connect(middleProxyBall.twoBoneLocator.inputs()[0].tx)
                middleProxyBall.jointPosition.connect(invNode.input1X)
                invNode.outputX.connect(middleProxyBall.twoBoneLocator.inputs()[1].tx)
            elif direction == 'vertical' :
                invNode.input2Y.set(-1)
                middleProxyBall.jointPosition.connect(middleProxyBall.twoBoneLocator.inputs()[0].ty)
                middleProxyBall.jointPosition.connect(invNode.input1Y)
                invNode.outputY.connect(middleProxyBall.twoBoneLocator.inputs()[1].ty)
            
                
    
    def removeTwoJoints (self):
        '''
        Remove control from the proxyBall to control the placement of 2  joints.
        '''
        middleProxyBall = self.proxyBall.inputs()[0]
        
        if middleProxyBall.jointPosition.exists() :
            
            # delete the attributes the 2 locator and the multiplyNode
            pm.delete(middleProxyBall.jointPosition.outputs()[0])
            for loc in middleProxyBall.twoBoneLocator.inputs() :
                pm.delete(loc)
            middleProxyBall.jointPosition.delete()
            middleProxyBall.twoBoneLocator.delete()
            
    
    def buildIkFKJnt (self):
        '''
        Duplicate the joint if needed.
        
        test if the parent node have ikJnt and fkJnt attribute.
        if the node have the two attribute duplicate the joint.
        '''
        parentNode = self.getParentNode()
        if parentNode.ik.get() and parentNode.fk.get() :
            # get the hips Joint or the Shoulder Joint
            baseJnt = parentNode.jnt.inputs()[0]
            
            #for suffix,connectTo in (('_ik',parentNode.ikJnt),('_fk', parentNode.fkJnt)) :
            for suffix,connectTo in (('_ik',parentNode.ikJnt),) :
                # when the joint are duplicate there is a strange behavior.
                # the new joint are not connected to the node (leg or arm)
                # but the connection of the old joint are doubled
                oldJointListSize = len(parentNode.jnt.inputs())
                newBaseJnt = baseJnt.duplicate(name=baseJnt.name()[:baseJnt.name().rfind('_')]+suffix,\
                                               renameChildren=True)[0]

                baseJntList = baseJnt.listRelatives(ad=True)
                baseJntList.append(baseJnt)
                baseJntList.reverse()
                
                if parentNode.twoJoints.get() :
                    numberOfJoint = 4
                else :
                    numberOfJoint = 3
                
                for index,joint in enumerate (baseJntList[:numberOfJoint]) :
                    joint._pantin.disconnect(parentNode.jnt[index+oldJointListSize])
                
                # connection to the input of the proxy node are duplicate to
                duplicateInputConnection = [input for input in baseJntList[numberOfJoint-1]._pantin\
                                            .outputs(plugs=True) if '_input' in input.name()][-1]
                baseJntList[numberOfJoint-1]._pantin.disconnect(duplicateInputConnection)
                    
                #newBaseJnt._pantin.connect(connectTo,na=True)
                
                #jointList = newBaseJnt.getChildren(allDescendents=True)
                #jointList.reverse()

                #for joint in jointList :
                #    joint.rename(joint.name()[:joint.name().rfind('_')]+suffix)
                #    joint._pantin.connect(connectTo,na=True)
                
    def DuplicateConnection (self,attr):
        '''
        Return the duplicate connection
        '''
        connectionList = [connection for connection in attr.outputs(plugs=True) if '[' in connection.name()]
        
        for index,connection in enumerate(connectionList) :
            if connection in connectionList[index+1] :
                pass

            
            

            
        
        
        
    
                
    
                
    
    
class WorldProxyNode (RiggingProxyNode):
    '''
    Proxy for the worldNode
    '''
    _nodeTypeID = 'WorldProxyNode'
    _suffix = 'worldProx'
    
    
    def buildProxy (self):
        if not self.proxyIsBuild() :
            inputName = self.getParentNode().listInput()[0]
            #self.buildProxyBall('green', 0.3, inputName,inputName)
            
            self.createProxyBallSG()
            name = self.buildProxyObjectName (inputName)
            proxyBall = pm.sphere(constructionHistory=False,name=name,ax=(0, 1, 0),radius=0.3,name=name)[0]
            
            # hide visibility,sx,sz, alias sy and connect it to sx and sz
            # worldProxy need to be scalable to allow the proxy to be scaled 
            utils.lockAndHideAttr(proxyBall, ('visibility',))
            pm.aliasAttr('proxyScale',proxyBall.sy)
            proxyBall.sx.set(channelBox=False,keyable=False)
            proxyBall.sz.set(channelBox=False,keyable=False)
            proxyBall.sy.connect(proxyBall.sx)
            proxyBall.sy.connect(proxyBall.sz)
        
            self.setProxyBallColor(proxyBall, 'green')
            proxyBall.addAttr('_pantin',at='message')
        
            proxyBall_grp = self.buildProxyGrp()[1]
            pm.parent (proxyBall,proxyBall_grp)

            self.connectProxyBall(proxyBall,inputName)
            
    def buildSkeleton (self):
        '''
        Build world_ctrl, walk_ctrl, ctrl_grp and parent  world_ctrl and walk_ctrl to ctrl_grp.
        '''
        characterName = self.getCharacterName()
        characterNode = self.getCharacterNode()
        
        # the world control are the first to be build
        # create the group and connect it to the characterNode
        ctrl_grp = pm.group(empty=True,name=characterName +'_ctrl_grp')
        ctrl_grp.addAttr('_pantin',at='message')
        ctrl_grp._pantin.connect(characterNode.ctrl_grp)
        utils.lockAndHideAttr(ctrl_grp, all=True)
        pm.parent(ctrl_grp,characterNode)
        
        
    def buildRig (self):
        '''
        Build the rig for the worlNode.
        '''
        characterName = self.getCharacterName()
        characterNode = self.getCharacterNode()
        ctrl_grp = characterNode.ctrl_grp.inputs()[0]
        skeletonMaster_grp = characterNode.skeletonMaster_grp.inputs()[0]
        
        # build the world ctrl
        worldCtrlName = characterName+'_world_ctrl'
        worldCtrl = pm.circle(name=worldCtrlName,radius=4.5,normal=(0,1,0),constructionHistory=False)[0]
        self.setupCtrl(worldCtrl)
        worldProxyBall = self.proxyBall.inputs()[0]
        utils.snap(worldCtrl, worldProxyBall)
        self.setColorOveride(worldCtrl, ctrlShape.yellow)
        utils.lockAndHideAttr(worldCtrl, ('visibility',))
        
        # build the walk ctrl
        walkCtrlName = characterName+'_walk_ctrl'
        walkCtrl = ctrlShape.buildCross(walkCtrlName)
        self.setupCtrl(walkCtrl)
        self.setColorOveride(walkCtrl, ctrlShape.brown)
        pm.parent(walkCtrl,worldCtrl)
        walkCtrl.translate.set(0,0,0)
        walkCtrl.rotate.set(0,0,0)
        utils.lockAndHideAttr(walkCtrl, ('visibility',))
        
        worldCtrl.setParent(ctrl_grp)
        
        self.buildConstraint('parent',walkCtrl,skeletonMaster_grp,maintainOffset=True,weight=1)
        self.buildConstraint('scale',walkCtrl,skeletonMaster_grp,maintainOffset=True,weight=1)

        
        
        
class RootAtomProxyNode (RiggingProxyNode):
    '''
    Proxy for the rootNode
    '''
    _nodeTypeID = 'RootAtomProxyNode'
    _suffix = 'rootProx'
    
    
    def buildProxy (self):
        if not self.proxyIsBuild() :
            inputName = self.getParentNode().listInput()[0]
            masterBall = self.buildProxyBall ('green',0.2,inputName,inputName)
            masterBall = self.connectProxyBallInput(masterBall)
            masterBall.ty.set(9)
            
class RootProxyNode (RiggingProxyNode):
    '''
    Proxy for the rootNode.
    '''
    _nodeTypeID = 'RootProxyNode'
    _suffix = 'rootProx'
    
    
    def buildProxy (self):
        if not self.proxyIsBuild() :
            inputName = self.getParentNode().listInput()[0]
            masterBall = self.buildProxyBall ('green',0.2,inputName,inputName)
            masterBall = self.connectProxyBallInput(masterBall)
            masterBall.ty.set(9)
            
            inputName = self.getParentNode().listInput()[1]
            leftBall = self.buildProxyBall('green', 0.15, inputName,inputName)
            pm.parent (leftBall,masterBall)
            self.buildProxyLink(masterBall, leftBall, 'root_left')
            leftBall.translate.set(0.4,0,0)
            
            inputName = self.getParentNode().listInput()[2]
            rightBall = self.buildProxyBall('green', 0.15, inputName,inputName)
            pm.parent (rightBall,masterBall)
            self.buildProxyLink(masterBall, rightBall, 'root_right')
            rightBall.translate.set(-0.4,0,0)
            
    def buildSkeleton (self):
        '''
        Build the joint for the Root node.
        '''
        
        root_c_jnt = self.buildJoint('root', 'master')
        proxyBall = self.master_input.inputs()[0]
        utils.snap(root_c_jnt, proxyBall,rotation=False)
        
        root_l_jnt = self.buildJoint('root', 'left')
        proxyBall = self.left_input.inputs()[0]
        utils.snap(root_l_jnt, proxyBall,rotation=False)
        root_l_jnt.setParent(root_c_jnt)
        
        root_r_jnt = self.buildJoint('root', 'right')
        proxyBall = self.right_input.inputs()[0]
        utils.snap(root_r_jnt, proxyBall,rotation=False)
        root_r_jnt.setParent(root_c_jnt)
        
    def buildRig (self):
        '''
        Build the rig for the rootNode
        '''
        cogCross = ctrlShape.buildCogCross('cogCross')
        cogCrossShape = cogCross.getShape()
        rootJnt = self.getParentNode().jnt.inputs()[0]
        cogCrossShape.setParent(rootJnt,shape=True,add=True)
        pm.delete(cogCross)
        
        
        
        
            
class BoneProxyNode (RiggingProxyNode):
    '''
    Proxy for the boneNode.
    '''
    _nodeTypeID = 'BoneProxyNode'
    _suffix = 'boneProx'
    
    
    def buildProxy(self):
        if not self.proxyIsBuild() :
            inputName = self.getParentNode().listInput()[0]
            masterBall = self.buildProxyBall ('green',0.2,inputName,inputName)
            masterBall = self.connectProxyBallInput(masterBall,proxyLink=True)
            if self.getParentNode().getSide() == 'l' :
                masterBall.translate.set(3,0,0)
            elif self.getParentNode().getSide() == 'r' :
                masterBall.translate.set(-3,0,0)
                
    def buildSkeleton(self):
        '''
        Build the skeleton for the BoneNode.
        '''
        joint = self.buildJoint(self.split('_')[2][:-2], 'master')
        proxyBall = self.master_input.inputs()[0]
        utils.snap(joint, proxyBall,rotation=False)
        
        parentJoint = self.getJointWhereToConnect()
        joint.setParent(parentJoint)
        
        parentJoint.orientJoint('xyz',secondaryAxisOrient='yup')
        if self.getParentNode().getSide() == 'r' :
            parentJoint.setRotateAxis((0,0,180))
                
class LegProxyNode (TwoJointsProxyNode):
    '''
    Proxy for the leg node
    '''
    _nodeTypeID = 'LegProxyNode'
    _suffix = 'legProx'
    
    
    def buildProxy(self):
        if not self.proxyIsBuild() :
            kneeBall = self.buildProxyBall('red', 0.15, 'knee')
            kneeBall = self.connectProxyBallInput(kneeBall,proxyLink=True)
            kneeBall.translate.set(0,-4,1)
            
            inputName = self.getParentNode().listInput()[0]
            masterBall = self.buildProxyBall ('green',0.2,inputName,inputName)
            masterBall = self.connectProxyBallInput(masterBall)
            masterBall.translate.set(0,-8,0)
            self.buildProxyLink(self.proxyBall.listConnections()[0], masterBall,'ankle')
            
            if self.getParentNode().twoJoints.get() :
                self.addTwoJoints()
                
    def buildSkeleton(self):
        '''
        Build the skeleton for the LegProxyNode.
        '''
        # legBase jnt
        parentJoint = self.getJointWhereToConnect()
        legBaseJnt = self.buildJoint('legBase')
        utils.snap(legBaseJnt, parentJoint, rotation=False)
        legBaseJnt.setParent(parentJoint)
        
        if self.getParentNode().twoJoints.get() :
            kneeLocA, kneeLocB = self.proxyBall.inputs()[0].twoBoneLocator.inputs()
            
            # kneeA jnt
            kneeAJnt = self.buildJoint('kneeA')
            utils.snap(kneeAJnt, kneeLocA,rotation=False)
            kneeAJnt.setParent(legBaseJnt)
            
            # orient hips jnt
            legBaseJnt.orientJoint('xyz',secondaryAxisOrient='yup')
            if self.getParentNode().getSide() == 'r' :
                legBaseJnt.setRotateAxis((0,0,180))
            
            # kneeB jnt
            kneeBJnt = self.buildJoint('kneeB')
            utils.snap(kneeBJnt, kneeLocB,rotation=False)
            kneeBJnt.setParent(kneeAJnt)
            
            # orient kneeAJnt
            kneeAJnt.orientJoint('xyz',secondaryAxisOrient='yup')
            if self.getParentNode().getSide() == 'r' :
                kneeAJnt.setRotateAxis((0,0,180))
            
            kneeJnt = kneeBJnt
            
        else :
            # knee jnt
            kneeBall = self.proxyBall.inputs()[0]
            kneeJnt = self.buildJoint('knee')
            utils.snap(kneeJnt, kneeBall,rotation=False)
            kneeJnt.setParent(legBaseJnt)
            
            # orient hips jnt
            legBaseJnt.orientJoint('xyz',secondaryAxisOrient='yup')
            if self.getParentNode().getSide() == 'r' :
                parentJoint.setRotateAxis((0,0,180))
            
        # ankle jnt
        ankleBall = self.master_input.inputs()[0]
        ankleJnt = self.buildJoint('ankle', 'master')
        utils.snap(ankleJnt, ankleBall,rotation=False)
        ankleJnt.setParent(kneeJnt)
        
        # orient knee jnt
        kneeJnt.orientJoint('xyz',secondaryAxisOrient='ydown')
        if self.getParentNode().getSide() == 'r' :
            kneeJnt.setRotateAxis((0,0,180))
            
            
    def addTwoJoints (self):
        '''
        Add control to the knee proxyBall to control the placement of 2 knee joints.
        '''
        if self.proxyIsBuild() :
            TwoJointsProxyNode.addTwoJoints(self, 'knee', 'vertical')
        
    def removeTwoJoints (self):
        '''
        Remove control from the knee proxyBall to control the placement of 2 knee joints.
        '''
        if self.proxyIsBuild() :
            TwoJointsProxyNode.removeTwoJoints(self)
            
    def buildRig (self):
        '''
        Build the rig for the leg Node
        '''
        self.buildIkFKJnt()
        
        
        
            
class FootProxyNode (RiggingProxyNode):
    '''
    Proxy for the foot node.
    '''
    _nodeTypeID = 'FootProxyNode'
    _suffix = 'footProx'
    
    
    def buildProxy(self):
        if not self.proxyIsBuild() :
            ballBall = self.buildProxyBall('red', 0.1, 'ball')
            ballBall = self.connectProxyBallInput(ballBall,proxyLink=True,proxyLinkName='ball')
            ballBall.translate.set(0,-1,1)
            
            toeBall = self.buildProxyBall('red', 0.1, 'toe')
            pm.parent(toeBall,ballBall)
            toeBall.translate.set(0,0,1)
            self.buildProxyLink(self.proxyBall.listConnections()[0], toeBall,'toe')
            
            outsideBall = self.buildProxyBall('red', 0.1, 'outside')
            outsideBall = self.connectProxyBallInput(outsideBall,proxyLink=True,proxyLinkName='outside')
            
            insideBall = self.buildProxyBall('red', 0.1, 'inside')
            insideBall = self.connectProxyBallInput(insideBall, proxyLink=True,proxyLinkName='inside')
            
            if self.getParentNode().getSide() == 'l' :
                outsideBall.translate.set(0.5,-1,0)
                insideBall.translate.set(-0.5,-1,0)
            elif self.getParentNode().getSide() == 'r' :
                outsideBall.translate.set(-0.5,-1,0)
                insideBall.translate.set(0.5,-1,0)
                
            heelBall = self.buildProxyBall('red', 0.1, 'heel')
            heelBall = self.connectProxyBallInput(heelBall, proxyLink=True)
            heelBall.translate.set(0,-1,-1)
            
    def buildSkeleton (self):
        # ball jnt
        ballBall = self.proxyBall.inputs()[0]
        ballJnt = self.buildJoint('ball')
        utils.snap(ballJnt, ballBall,rotation=False)
        parentJoint = self.getJointWhereToConnect()
        ballJnt.setParent(parentJoint)
        
        # orient ankleJnt
        parentJoint.orientJoint('xyz',secondaryAxisOrient='yup')
        if self.getParentNode().getSide() == 'r' :
            parentJoint.setRotateAxis((0,0,180))
            
        # toe jnt
        toeBall = self.proxyBall.inputs()[1]
        toeJnt = self.buildJoint('toe')
        utils.snap(toeJnt, toeBall,rotation=False)
        toeJnt.setParent(ballJnt)
        
        # orient ball jnt
        ballJnt.orientJoint('xyz',secondaryAxisOrient='yup')
        if self.getParentNode().getSide() == 'r' :
            ballJnt.setRotateAxis((0,0,180))
            
        # orient toe jnt
        toeJnt.orientJoint ('none',secondaryAxisOrient='yup')
        
        
            
class SpineAtomProxyNode (RiggingProxyNode):
    '''
    Proxy for the spine node.
    '''
    _nodeTypeID = 'SpineAtomProxyNode'
    _suffix = 'spineProx'
    
    def buildProxy(self):
        if not self.proxyIsBuild():
            inputName = self.getParentNode().listInput()[0]
            masterBall = self.buildProxyBall('red', 0.2, inputName,inputName)
            masterBall = self.connectProxyBallInput(masterBall)
            masterBall.translate.set(0,9,0)
            
            aBall = self.buildProxyBall('red', 0.2, 'a')
            aBall = self.connectProxyBallInput(aBall)
            aBall.translate.set(0,3,0)
            
            bBall = self.buildProxyBall('red', 0.2, 'b')
            bBall = self.connectProxyBallInput(bBall)
            bBall.translate.set(0,6,0)
            
            parentBallName = self.getProxyBallWhereToConnect()
            
            self.buildProxySpline('spine01', (parentBallName,aBall,bBall,masterBall), 3)
            
class SpineProxyNode (RiggingProxyNode):
    '''
    Proxy for the spine node.
    '''
    _nodeTypeID = 'SpineProxyNode'
    _suffix = 'spineProx'
    
    def buildProxy(self):
        if not self.proxyIsBuild():
            inputName = self.getParentNode().listInput()[0]
            masterBall = self.buildProxyBall('red', 0.2, inputName,inputName)
            masterBall = self.connectProxyBallInput(masterBall)
            masterBall.translate.set(0,9,0)
            
            inputName = self.getParentNode().listInput()[1]
            leftBall = self.buildProxyBall('red', 0.15, inputName,inputName)
            pm.parent (leftBall,masterBall)
            self.buildProxyLink(masterBall, leftBall, 'spine_left')
            leftBall.translate.set(0.4,0,0)
            
            inputName = self.getParentNode().listInput()[2]
            rightBall = self.buildProxyBall('red', 0.15, inputName,inputName)
            pm.parent (rightBall,masterBall)
            self.buildProxyLink(masterBall, rightBall, 'spine_right')
            rightBall.translate.set(-0.4,0,0)
            
            aBall = self.buildProxyBall('red', 0.2, 'a')
            aBall = self.connectProxyBallInput(aBall)
            aBall.translate.set(0,3,0)
            
            bBall = self.buildProxyBall('red', 0.2, 'b')
            bBall = self.connectProxyBallInput(bBall)
            bBall.translate.set(0,6,0)
            
            parentBallName = self.getProxyBallWhereToConnect()
            
            self.buildProxySpline('spine01', (parentBallName,aBall,bBall,masterBall), 3)
            
    def buildSkeleton (self):
        spineSpline = self.proxySpline.inputs()[0]
        jointNumber = self.getParentNode().jointNumber.get()
        
        # rebuild to guide the creation of the joint
        pm.rebuildCurve(spineSpline,degree=1,spans=jointNumber,ch=True)
        
        pm.select(cl=True)
        
        for i in xrange(jointNumber+1) :
            # get the position of the control point and build the joint
            jointPos = pm.xform(spineSpline.cp[i],query=True,worldSpace=True,translation=True)
            jointName = self.buildJointName('spine'+chr(65+i))
            joint = pm.joint(name=jointName,position=jointPos)
            
            joint.addAttr('_pantin',at='message')
            
            if i == jointNumber :
                self.connectJoint(joint,'master')
            else :
                self.connectJoint(joint)
            
            if i == 0 :
                pm.parent(joint,self.buildSkeletonGrp())
            else :
                parentJoint = self.getParentNode().jnt.inputs()[-2] # get the parent of the joint
                parentJoint.orientJoint('xyz',secondaryAxisOrient='zup')
                
        # left input joint
        spineEnd_c_jnt = self.master_input.inputs()[1]
        spine_l_jnt = self.buildJoint('spine', 'left')
        proxyBall = self.left_input.inputs()[0]
        utils.snap(spine_l_jnt, proxyBall,rotation=False)
        spine_l_jnt.setParent(spineEnd_c_jnt)
        
        # right input joint
        spine_r_jnt = self.buildJoint('spine', 'right')
        proxyBall = self.right_input.inputs()[0]
        utils.snap(spine_r_jnt, proxyBall,rotation=False)
        spine_r_jnt.setParent(spineEnd_c_jnt)
                
        
        
        
            
class ClavicleProxyNode (RiggingProxyNode):
    '''
    Proxy for the clavicle node
    '''
    _nodeTypeID = 'ClavicleProxyNode'
    _suffix = 'clavProx'
    
    def buildProxy(self):
        if not self.proxyIsBuild() :
            inputName = self.getParentNode().listInput()[0]
            masterBall = self.buildProxyBall ('green',0.2,inputName,inputName)
            masterBall = self.connectProxyBallInput(masterBall,proxyLink=True)
            
            if self.getParentNode().getSide() == 'l' :
                masterBall.translate.set(2,0,0)
            elif self.getParentNode().getSide() == 'r' :
                masterBall.translate.set(-2,0,0)
                
    def buildSkeleton(self):
        proxyBall = self.master_input.inputs()[0]
        joint = self.buildJoint('clavicle', 'master')
        utils.snap(joint, proxyBall,rotation=False)
        
        parentJoint = self.getJointWhereToConnect()
        joint.setParent(parentJoint)
        
        parentJoint.orientJoint('xyz',secondaryAxisOrient='yup')
        if self.getParentNode().getSide() == 'r' :
            parentJoint.setRotateAxis((0,0,180))
        
        
                
class ArmProxyNode (TwoJointsProxyNode):
    '''
    Proxy for the arm node
    '''
    _nodeTypeID = 'ArmProxyNode'
    _suffix = 'armProx'
    
    def buildProxy(self):
        if not self.proxyIsBuild() :
            elbowBall = self.buildProxyBall('red', 0.15, 'elbow')
            elbowBall = self.connectProxyBallInput(elbowBall,proxyLink=True)
            
            inputName = self.getParentNode().listInput()[0]
            masterBall = self.buildProxyBall ('green',0.2,inputName,inputName)
            masterBall = self.connectProxyBallInput(masterBall)
            self.buildProxyLink(self.proxyBall.inputs()[0], masterBall,'wrist')
            
            if self.getParentNode().getSide() == 'l' :
                elbowBall.translate.set(4,0,-0.5)
                masterBall.translate.set(8,0,0)
            elif self.getParentNode().getSide() == 'r' :
                elbowBall.translate.set(-4,0,-0.5)
                masterBall.translate.set(-8,0,0)
            
            if self.getParentNode().twoJoints.get() == True :
                self.addTwoJoints()
                
    def buildSkeleton (self):
        if self.getParentNode().twoJoints.get() :
            elbowLocA, elbowLocB = self.proxyBall.inputs()[0].twoBoneLocator.inputs()
            
            # elbowA jnt
            elbowAJnt = self.buildJoint('elbowA')
            utils.snap(elbowAJnt, elbowLocA,rotation=False)
            parentJoint = self.getJointWhereToConnect()
            elbowAJnt.setParent(parentJoint)
            
            # orient clavicle jnt
            parentJoint.orientJoint('xyz',secondaryAxisOrient='yup')
            if self.getParentNode().getSide() == 'r' :
                parentJoint.setRotateAxis((0,0,180))
            
            # elbowB jnt
            elbowBJnt = self.buildJoint('elbowB')
            utils.snap(elbowBJnt, elbowLocB,rotation=False)
            elbowBJnt.setParent(elbowAJnt)
            
            # orient kneeAJnt
            elbowAJnt.orientJoint('xyz',secondaryAxisOrient='yup')
            if self.getParentNode().getSide() == 'r' :
                elbowAJnt.setRotateAxis((0,0,180))
            
            elbowJnt = elbowBJnt
            
        else :
            # elbow jnt
            elbowBall = self.proxyBall.inputs()[0]
            elbowJnt = self.buildJoint('elbow')
            utils.snap(elbowJnt, elbowBall,rotation=False)
            parentJoint = self.getJointWhereToConnect()
            elbowJnt.setParent(parentJoint)
            
            # orient clavicle jnt
            parentJoint.orientJoint('xyz',secondaryAxisOrient='yup')
            if self.getParentNode().getSide() == 'r' :
                parentJoint.setRotateAxis((0,0,180))
            
        # wrist jnt
        wristBall = self.master_input.inputs()[0]
        wristJnt = self.buildJoint('wrist', 'master')
        utils.snap(wristJnt, wristBall,rotation=False)
        wristJnt.setParent(elbowJnt)
        wristJnt.orientJoint('none')
        
        # orient elbow jnt
        elbowJnt.orientJoint('xyz',secondaryAxisOrient='ydown')
        if self.getParentNode().getSide() == 'r' :
            wristJnt.setRotateAxis((0,0,180))
                
    def addTwoJoints (self):
        '''
        Add control to the elbow proxyBall to control the placement of 2 knee joints.
        '''
        if self.proxyIsBuild() :
            TwoJointsProxyNode.addTwoJoints(self, 'elbow', 'horizontal')
            
    def removeTwoJoints (self):
        '''
        Remove control from the elbow proxyBall to control the placement of 2 knee joints.
        '''
        if self.proxyIsBuild() :
            TwoJointsProxyNode.removeTwoJoints(self)
            
class NeckProxyNode (RiggingProxyNode):
    '''
    Proxy for the arm node.
    '''
    _nodeTypeID = 'NeckProxyNode'
    _suffix = 'neckProx'
    
    def buildProxy(self):
        if not self.proxyIsBuild() :
            inputName = self.getParentNode().listInput()[0]
            masterBall = self.buildProxyBall ('green',0.2,inputName,inputName)
            masterBall = self.connectProxyBallInput(masterBall,proxyLink=True)
            masterBall.translate.set(0,2,0)
            
    def addMiddleControl (self):
        '''
        Add a proxyBall to control the curvature of the neck
        '''
        if len(self.proxyBall.inputs()) == 1 :
            pm.delete (self.proxyLink.inputs()[0])
            middleBall = self.buildProxyBall('red', 0.1, 'a')
        
            parentBallName = self.getProxyBallWhereToConnect()
            masterBall = self.master_input.inputs()[0]
        
            pm.delete(pm.pointConstraint(masterBall,parentBallName,middleBall,weight=1))
            middleBall = self.connectProxyBallInput(middleBall,proxyLink=False)
            self.buildProxySpline('neck01', (parentBallName,middleBall,masterBall), 2)
        
    def removeMiddleControl (self):
        '''
        Remove the proxyBall that control the curvature of the neck
        '''
        if len(self.proxyBall.inputs()) >= 2 :
            pm.delete (self.proxyBall.inputs()[1])
            pm.delete (self.proxySpline.inputs()[0])
        
            parentBallName = self.getProxyBallWhereToConnect()
            masterBall = self.master_input.inputs()[0]
            self.buildProxyLink(parentBallName, masterBall)
        
    def buildSkeleton (self):
        '''
        Build the skeleton for the neckNode.
        '''
        jointNumber = self.getParentNode().jointNumber.get()
        
        if jointNumber == 1 :
            proxyBall = self.master_input.inputs()[0]
            joint = self.buildJoint('neck', 'master')
            utils.snap(joint, proxyBall,rotation=False)
            
            parentJoint = self.getJointWhereToConnect()
            joint.setParent(parentJoint)
            
            parentJoint.orientJoint('xyz',secondaryAxisOrient='ydown')
            
        else :
            proxySpline = self.proxySpline.inputs()[0]
        
            # rebuild to guide the creation of the joint
            pm.rebuildCurve(proxySpline,degree=1,spans=jointNumber,ch=True)
        
            pm.select(cl=True)
            
            for i in xrange(jointNumber+1) :
                # get the position of the control point and build the joint
                jointPos = pm.xform(proxySpline.cp[i],query=True,worldSpace=True,translation=True)
                jointName = self.buildJointName('neck'+chr(65+i))
                joint = pm.joint(name=jointName,position=jointPos)
            
                joint.addAttr('_pantin',at='message')
            
                if i == jointNumber :
                    self.connectJoint(joint,'master')
                else :
                    self.connectJoint(joint)
            
                if i == 0 :
                    joint.setParent(self.getJointWhereToConnect())
                else :
                    parentJoint = self.getParentNode().jnt.inputs()[-2] # get the parent of the joint
                    parentJoint.orientJoint('xyz',secondaryAxisOrient='yup')
        
        
class HeadProxyNode (RiggingProxyNode):
    '''
    Proxy for the Head node.
    '''
    _nodeTypeID = 'HeadProxyNode'
    _suffix = 'headProx'
    
    def buildProxy (self):
        if not self.proxyIsBuild() :
            l_eyes = self.buildProxyBall('red', 0.1, 'l_eyes')
            l_eyes = self.connectProxyBallInput(l_eyes,proxyLink=True,proxyLinkName='l_eyes')
            l_eyes.translate.set(1,2.5,1.5)
            
            r_eyes = self.buildProxyBall('red', 0.1, 'r_eyes')
            r_eyes = self.connectProxyBallInput(r_eyes,proxyLink=True,proxyLinkName='r_eyes')
            r_eyes.translate.set(-1,2.5,1.5)
            
            l_ears_start = self.buildProxyBall('red', 0.1, 'l_ears_start')
            l_ears_start = self.connectProxyBallInput(l_ears_start,proxyLink=True,proxyLinkName='l_ears_start')
            l_ears_start.translate.set(2.5,2,0)
            
            l_ears_end = self.buildProxyBall('red', 0.1, 'l_ears_end')
            pm.parent(l_ears_end,l_ears_start)
            l_ears_end.translate.set(1,0,0)
            self.buildProxyLink(l_ears_start, l_ears_end,'l_ears_end')
            
            r_ears_start = self.buildProxyBall('red', 0.1, 'r_ears_start')
            r_ears_start = self.connectProxyBallInput(r_ears_start,proxyLink=True,proxyLinkName='r_ears_start')
            r_ears_start.translate.set(-2.5,2,0)
            
            r_ears_end = self.buildProxyBall('red', 0.1, 'r_ears_end')
            pm.parent(r_ears_end,r_ears_start)
            r_ears_end.translate.set(-1,0,0)
            self.buildProxyLink(r_ears_start, r_ears_end,'r_ears_end')
            
            top = self.buildProxyBall('blue', 0.1, 'top')
            top = self.connectProxyBallInput(top,proxyLink=True,proxyLinkName='top')
            top.translate.set(0,4,0)
            
    def buildSkeleton (self):
        '''
        Build the skeleton for the HeadNode.
        '''
        proxyBallList = self.proxyBall.inputs()
        
        # build the eyes joints
        for i,side in enumerate(['l','r']) :
            jointName = self.buildJointName('eye', side=side)
            pm.select(cl=True)
            eyeJoint = pm.joint(name = jointName)
            eyeJoint.addAttr('_pantin',at='message')
            self.connectJoint(eyeJoint)
            utils.snap(eyeJoint, proxyBallList[i],rotation=False)
            eyeJoint.setParent(self.getJointWhereToConnect())
            
        #build the ears joints
        for i,side in enumerate(['l','r']) :
            jointName = self.buildJointName('earA', side=side)
            pm.select(cl=True)
            earStart = pm.Joint(name=jointName)
            earStart.addAttr('_pantin',at='message')
            self.connectJoint(earStart)
            utils.snap(earStart,proxyBallList[2+(i*2)],rotation=False)
            earStart.setParent(self.getJointWhereToConnect())
            
            jointName = self.buildJointName('earB', side=side)
            pm.select(cl=True)
            earEnd = pm.Joint(name=jointName)
            earEnd.addAttr('_pantin',at='message')
            self.connectJoint(earEnd)
            utils.snap(earEnd,proxyBallList[3+(i*2)],rotation=False)
            earEnd.setParent(earStart)
            
        # build head joint
        pm.select(cl=True)
        headJoint = self.buildJoint('head')
        utils.snap(headJoint,proxyBallList[6],rotation=False)
        headJoint.setParent(self.getJointWhereToConnect())
        
        
            
class HandProxyNode (RiggingProxyNode):
    '''
    Proxy for the Hand node.
    '''
    _nodeTypeID = 'HandProxyNode'
    _suffix = 'handProx'
    
    def buildProxy (self):
        if not self.proxyIsBuild() :
            
            if self.getParentNode().getSide() == 'l' :
                side = 1
            else :
                side = -1
                
            
            # thumb building
            baseThumb = self.buildProxyBall('red', 0.06, 'thumb01')
            baseThumb = self.connectProxyBallInput(baseThumb, proxyLink=True, proxyLinkName='baseThumb')
            baseThumb.translate.set(0.5*side,0,0.4)
            
            thumbA = self.buildProxyBall('red', 0.06, 'thumb02')
            pm.parent(thumbA,baseThumb)
            self.buildProxyLink(baseThumb,thumbA,'thumb02')
            thumbA.translate.set(0.15*side,0,0.5)
            thumbA.rotate.set(0,-45*side,0)
            
            thumbB = self.buildProxyBall('red', 0.06, 'thumb03')
            pm.parent(thumbB,thumbA)
            self.buildProxyLink(thumbA,thumbB,'thumb03')
            thumbB.translate.set(0.5*side,0,0)
            thumbB.rotate.set(0,0,0)
            
            thumbC = self.buildProxyBall('red', 0.06, 'thumb04')
            pm.parent(thumbC,thumbB)
            self.buildProxyLink(thumbB,thumbC,'thumb04')
            thumbC.translate.set(0.5*side,0,0)
            
            # fingers building
            fingersList = list()
            zPositionList = self.calculateFingerPos ()
            
            for i in xrange(self.getParentNode().fingerNumber.get()) :
                fingersList.append(list())
                fingersList[i].append (self.buildProxyBall('red', 0.06, 'finger'+chr(65+i)+'01'))
                fingersList[i][0] = self.connectProxyBallInput(fingersList[i][0], proxyLink=True, proxyLinkName='baseFinger'+chr(65+i))
                fingersList[i][0].translate.set(1*side,0,zPositionList[i])
                
                fingerPos = [0.6,0.5,0.4]
                for fingerNum in xrange (1,4) :
                    newFingerName = 'finger%s%#02d'%(chr(65+i),fingerNum+1)
                    fingersList[i].append (self.buildProxyBall('red', 0.06, newFingerName))
                    pm.parent(fingersList[i][fingerNum], fingersList[i][fingerNum-1])
                    self.buildProxyLink(fingersList[i][fingerNum-1],fingersList[i][fingerNum],newFingerName)
                    #fingersList[i][fingerNum].translate.set(0.5*side,0,0)
                    fingersList[i][fingerNum].translate.set(fingerPos[fingerNum-1]*side,0,0)
                    
    def buildSkeleton (self):
        '''
        Build the skeleton for the handNode.
        '''
        proxyBallList = self.proxyBall.inputs()
        
        # build thumb if needed      
        if self.getParentNode().thumb.get() :
         # test if a bone with the same name already exist
            nameLetterIndex = 0
            for i in xrange(1000) :
                name = self.buildJointName('thumb%s'%(chr(65+i)))
                if not pm.objExists(name) :
                    nameLetterIndex = 65+i
                    break
            
            for i in xrange(4) :
                thumbJnt = self.buildJoint('thumb%s'%(chr(nameLetterIndex+i)))
                proxyBall = proxyBallList.pop(0)
                utils.snap(thumbJnt, proxyBall,rotation=False)
                if i == 0 :
                    thumbJnt.setParent(self.getJointWhereToConnect())
                else :
                    thumbJnt.setParent(oldTumbJoint)
                oldTumbJoint = thumbJnt
                
        for iFinger in xrange (self.getParentNode().fingerNumber.get()) :
            for i in xrange (4) :
                fingerJnt = self.buildJoint('finger%s'%(chr(65+iFinger)))
                proxyBall = proxyBallList.pop(0)
                utils.snap(fingerJnt,proxyBall,rotation=False)
                if i == 0 :
                    fingerJnt.setParent(self.getJointWhereToConnect())
                else :
                    fingerJnt.setParent(oldFingerJoint)
                    oldFingerJoint.orientJoint('xyz',secondaryAxisOrient='yup')
                oldFingerJoint = fingerJnt
                if i == 3 :
                    fingerJnt.orientJoint('none')
        
                    
    def calculateFingerPos (self):
        '''
        calculate the position of the finger and return a list of z position
        '''
        numberOfFinger = self.getParentNode().fingerNumber.get()
        if numberOfFinger == 1 :
            return [0]
        if numberOfFinger == 2 :
            return [-0.3,0.3]
        if numberOfFinger > 2 :
            positionList = list ()
            positionList.append(-0.6) # start position in Z
            step = 1.2 / (numberOfFinger-1)
            for counter in xrange (0,numberOfFinger-1) :
                positionList.append(positionList[counter]+step)
            return positionList
                
            
        
            
            
        
def proxyFactory (parentNode):
    '''
    Build the proxy node based on the type of the rigging node
    that call the fontction.
    
    param : parentNode 
    '''
    parentNodeType = parentNode.getNodeType()
    newNodeName = parentNode[:parentNode.rfind('_')]+'_pantProxy'
    
    className = parentNodeType +'ProxyNode'
    pantinObject = globals()[className]
    
    return pantinObject (newNodeName,create=True,connectTo=parentNode)

def registerVirtualNode ():
    pm._factories.registerVirtualClass(CharacterNode, nameRequired=False)
    pm._factories.registerVirtualClass(WorldNode, nameRequired=False)
    pm._factories.registerVirtualClass(RootAtomNode, nameRequired=False)
    pm._factories.registerVirtualClass(RootNode, nameRequired=False)
    pm._factories.registerVirtualClass(BoneNode, nameRequired=False)
    pm._factories.registerVirtualClass(LegNode, nameRequired=False)
    pm._factories.registerVirtualClass(FootNode, nameRequired=False)
    pm._factories.registerVirtualClass(SpineAtomNode, nameRequired=False)
    pm._factories.registerVirtualClass(SpineNode, nameRequired=False)
    pm._factories.registerVirtualClass(ClavicleNode, nameRequired=False)
    pm._factories.registerVirtualClass(ArmNode, nameRequired=False)
    pm._factories.registerVirtualClass(NeckNode, nameRequired=False)
    pm._factories.registerVirtualClass(HeadNode, nameRequired=False)
    pm._factories.registerVirtualClass(HandNode, nameRequired=False)
    
    pm._factories.registerVirtualClass(WorldProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(RootAtomProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(RootProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(BoneProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(LegProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(FootProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(SpineAtomProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(SpineProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(ClavicleProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(ArmProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(NeckProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(HeadProxyNode, nameRequired=False)
    pm._factories.registerVirtualClass(HandProxyNode, nameRequired=False)
    
    
    